package edu.gmu.atelier;

/**
 * Convenience methods for single and double machine epsilon.  Note reference
 * the definition of machine epsilon - it is the largest number that can
 * be added to 1.0 such that 1.0 + e > 1.0, or said another way it is
 * the maximum round off that can occur, i.e. interval between 1.0 and
 * the next largest floating-point number.
 * <p>
 * This definition is disputable, it may also be the smallest number such
 * that 1.0 + e > 1.0.  This is important because it is the difference 
 * between 2^53 or 2^52 respectively.
 * <p>
 * The equals methods are all absolute error measurements - for relative
 * you are on your own.
 * @author James H. Pope
 */
public class EpsilonUtil
{
    /*
     *  Machine epsilon 1.1920929E-7
     *  Machine epsilon 1.1920929E-7
     *  Machine epsilon 2.220446049250313E-16
     *  Machine epsilon 2.220446049250313E-16
     */
    public static final float SINGLE_EPS  = 1.1920929E-7f;
    public static final double DOUBLE_EPS = 2.220446049250313E-16;
    
    public static boolean singleEquals( float f1, float f2 )
    {
        //return Math.abs( f1-f2 ) >= SINGLE_EPS;
        return Math.abs( f1-f2 ) <  SINGLE_EPS;
    }
    
    public static boolean doubleEquals( double d1, double d2, int signDigits )
    {
        //return Math.abs( d1-d2 ) >= DOUBLE_EPS;
        return Math.abs( d1-d2 ) <  (DOUBLE_EPS * Math.pow(2, signDigits) );
    }
    
    public static boolean doubleEquals( double d1, double d2 )
    {
        //return Math.abs( d1-d2 ) >= DOUBLE_EPS;
        return Math.abs( d1-d2 ) <  DOUBLE_EPS;
    }
    
    public static boolean doubleEquals( double d1, double d2, double e )
    {
        //return Math.abs( d1-d2 ) >= DOUBLE_EPS;
        return Math.abs( d1-d2 ) <  e;
    }
    
    
//    private Epsilon(double eps)
//    {
//        
//    }
    
    //------------------------------------------------------------------------//
    // Static methods to compute machine epsilon.
    // Taken from Java numerical computing
    //------------------------------------------------------------------------//
    
    public static float calculateSingleEps()
    {
        // Find double epsilon
        float e = 0.5f;
        while( 1.0f+e != 1.0f )
        {
            e = e / 2.0f;
        }
        // Went past one too many, back up one then return
        return e*2.0f;
    }
    
    public static double calculateDoubleEps()
    {
        // Find double epsilon
        double e = 0.5;
        while( 1.0+e != 1.0 )
        {
            e = e / 2.0;
        }
        // Went past one too many, back up one then return
        return e*2.0;
    }
    
    // Taken from http://en.wikipedia.org/wiki/Machine_epsilon
    public static float calculateSingleEpsilon()
    {
        float machEps = 1.0f;
 
        do
        {
           machEps /= 2.0f;
        }
        while ((float) (1.0 + (machEps / 2.0)) != 1.0);
 
        return machEps;
    }
    
    public static double calculateDoubleEpsilon()
    {
        double machEps = 1.0;
 
        do
        {
           machEps /= 2.0;
        }
        while ( (1.0 + (machEps / 2.0)) != 1.0);
 
        return machEps;
    }
    
}
